
#include <qglobal.h>
#include <QDebug>

#include "qa39c.h"
#include "modbus/modbus.h"



QA39C::QA39C(QObject *parent)
    : QThread{parent}
{
    ctx= NULL;
    cnt_retry= 1;           //不重试。
    interval_retry= 10;     //
    slave_id= 1;            //从机地址1,是板载称重单元，目前只提供板载电池的电量。
    rsps.len= 4;            //最多4个称重板。

    cnt_txrx= 0;

    init_modbus();

    init_rsps();
}



/*打开A39C的供电，并执行libmodbus的连接。
*/
int32_t QA39C::init_modbus()
{
    pwr_a39c(PWR_ON);


    /*测试libmodbus源代码。
    */
    QString tty_ModbusRTU="/dev/ttyS2";     //肯定不是"ttyS2"，因为是文件名，得是"/dev/ttyS2"。

    QByteArray  array  = tty_ModbusRTU.toLatin1();
    const char *device = array.data();


    //以串口的方式创建libmobus实例,并设置参数(波特率暂定19200)
    ctx = modbus_new_rtu(device, 19200, 'N', 8, 1);
    if (NULL == ctx){
        //fprintf(stderr, "Unable to allocate libmodbus contex\n");
        //fflush(stdout);
        fprintf(stderr, "L%d %s\n", __LINE__, modbus_strerror(errno));
        fflush(stdout);

        qDebug()<<"Unable to allocate libmodbus contex\n";

        return -1;
    }

    modbus_set_debug(ctx, 0);           //设置1可看到调试信息
    modbus_set_slave(ctx, slave_id);    //设置slave ID

    modbus_set_response_timeout(ctx, 0,500000);   //超时相应时间：500ms.


    if (modbus_connect(ctx) == -1)      //等待连接设备
    {
        fprintf(stderr, "Connection failed:%s\n", modbus_strerror(errno));
        fflush(stdout);
        return -1;
    }

    qDebug()<<"ok:modbus _new_rtu";
    return 0;
}



/*控制A39Cm模块的电源。
 * 输入参数 state:0---关闭，其他---打开。
*/
void QA39C::pwr_a39c(qint8 state)
{
    //王楠4G控制的代码:
    QString path = "/sys/class/gpio/gpio195";
    /* 由于system函数只能用char类型，所以进行了转换 */
    /* export */
    QString cmd_export = "echo 195 > /sys/class/gpio/export";
    QByteArray cmdby_export = cmd_export.toLatin1();
    char* charCmd_export = cmdby_export.data();
    /* config */
    QString cmd_dir = "echo out >"+ path +"/direction";
    QByteArray cmdby_dir = cmd_dir.toLatin1();
    char* charCmd_dir = cmdby_dir.data();
    /* 关 */
    QString cmd_off = "echo 0 >"+ path +"/value";
    QByteArray cmdby_off = cmd_off.toLatin1();
    char* charCmd_off = cmdby_off.data();
    /* 开 */
    QString cmd_on = "echo 1 >"+ path +"/value";
    QByteArray cmdby_on = cmd_on.toLatin1();
    char* charCmd_on = cmdby_on.data();

    /* 导出GPIO */
    system(charCmd_export);
    /* 设置GPIO的输入输出状态 */
    system(charCmd_dir);

    if(state){  //打开电源。
        system(charCmd_on);
        QThread::msleep(2*1000);
        system(charCmd_on);
    }
    else{       //关闭电眼。
        system(charCmd_off);
        QThread::msleep(1000);
    }
}


/*
*/
void QA39C::init_rsps()
{
    for(qint8 i= 0; i< 5; i++){
        rsps.rsp_data[i].len= -1;
        rsps.rsp_data[i].unecho_cnt= 0;
        rsps.rsp_data[i].unlink= 0;

        for(qint8 j= 0; j< 6; j++)
            rsps.rsp_data[i].data[j]= 0;
    }
}



/*重载的线程函数。目前只执行定时轮询的工作。一次性访问，不在这里执行。
*/
void QA39C::run()
{
    int rc;
    //rsp.len= -1;
    qint8 idx= 0;
    RSP_DATA* prsp;


    //执行称重板清零。
    if(flag_op_zero){
        flag_op_zero= 0;

        #ifdef DEBUG_A39C
        qDebug()<<"op:zero";  //彩屏板载称重单元返回的电量（几格）。
        #endif

        do_zero();

        return;             //线程函数中只执行1个操作。
    }


    rsps.rsp_data[DATA_IDX_CP].len= -1;

    cnt_txrx++;
    if(3<= cnt_txrx){ //查询本机电量。
        cnt_txrx= 0;

        //遍历称重板。
        prsp= &rsps.rsp_data[DATA_IDX_CP];
        modbus_set_slave(ctx, SLAVE_ID_CP);   //彩屏板载称重单元地址。

        rc = modbus_read_registers(ctx, 2, 1, prsp->data);

        if (rc == -1)   //读取保持寄存器的值，可读取多个连续输入保持寄存器
        {
            //fprintf(stderr, "%s\n", modbus_strerror(errno));
            fprintf(stderr, "L%d %s\n", __LINE__, modbus_strerror(errno));
            fflush(stdout);

        }

        prsp->len= rc;

#ifdef DEBUG_A39C
        qDebug()<<"CP bat"<<prsp->len<<hex<<prsp->data[0];  //彩屏板载称重单元返回的电量（几格）。
#endif

        emit this->finish(rsps);

        return;     //线程函数中只执行1个操作，即执行了查询板载称重单元，就不会查询称重板。
    }




    //遍历称重板。
    prsp= &rsps.rsp_data[DATA_IDX_LF];
    modbus_set_slave(ctx, SLAVE_ID_LF);   //从机地址。左前轮：2, 左后轮：3, 右前轮：4, 右后轮：5。

    rc = modbus_read_registers(ctx, 0, 6, prsp->data);

    if (rc == -1)   //读取保持寄存器的值，可读取多个连续输入保持寄存器
    {
        //fprintf(stderr, "%s\n", modbus_strerror(errno));
        fprintf(stderr, "L%d %s\n", __LINE__, modbus_strerror(errno));
        fflush(stdout);

        prsp->unecho_cnt++;
        if(3<= prsp->unecho_cnt){
            prsp->unecho_cnt= 0;
            prsp->unlink= 1;
        }
    }
    else{
        prsp->unlink= 0;
        prsp->unecho_cnt= 0;
    }

    prsp->len= rc;

#ifdef DEBUG_A39C
    qDebug()<<SLAVE_ID_LF<<prsp->len<<hex<<prsp->data[0]<<prsp->data[1]<<prsp->data[2];  //实时重量和状态。
#endif

    QThread::msleep(10);


    //左后轮：
    prsp= &rsps.rsp_data[DATA_IDX_LE];
    modbus_set_slave(ctx, SLAVE_ID_LE);   //从机地址。左前轮：2, 左后轮：3, 右前轮：4, 右后轮：5。

    rc = modbus_read_registers(ctx, 0, 6, prsp->data);

    if (rc == -1)   //读取保持寄存器的值，可读取多个连续输入保持寄存器
    {
        //fprintf(stderr, "%s\n", modbus_strerror(errno));
        fprintf(stderr, "L%d %s\n", __LINE__, modbus_strerror(errno));
        fflush(stdout);

        prsp->unecho_cnt++;
        if(3<= prsp->unecho_cnt){
            prsp->unecho_cnt= 0;
            prsp->unlink= 1;
        }
    }
    else{
        prsp->unlink= 0;
        prsp->unecho_cnt= 0;
    }

    prsp->len= rc;

#ifdef DEBUG_A39C
    qDebug()<<SLAVE_ID_LE<<prsp->len<<hex<<prsp->data[0]<<prsp->data[1]<<prsp->data[2];  //实时重量和状态。
#endif

    QThread::msleep(10);


    //右前轮：
    prsp= &rsps.rsp_data[DATA_IDX_RF];
    modbus_set_slave(ctx, SLAVE_ID_RF);   //从机地址。左前轮：2, 左后轮：3, 右前轮：4, 右后轮：5。

    rc = modbus_read_registers(ctx, 0, 6, prsp->data);

    if (rc == -1)   //读取保持寄存器的值，可读取多个连续输入保持寄存器
    {
        //fprintf(stderr, "%s\n", modbus_strerror(errno));
        fprintf(stderr, "L%d %s\n", __LINE__, modbus_strerror(errno));
        fflush(stdout);

        prsp->unecho_cnt++;
        if(3<= prsp->unecho_cnt){
            prsp->unecho_cnt= 0;
            prsp->unlink= 1;
        }
    }
    else{
        prsp->unlink= 0;
        prsp->unecho_cnt= 0;
    }

    prsp->len= rc;

#ifdef DEBUG_A39C
    qDebug()<<SLAVE_ID_RF<<prsp->len<<hex<<prsp->data[0]<<prsp->data[1]<<prsp->data[2];  //实时重量和状态。
#endif

    QThread::msleep(10);


    //右后轮：
    prsp= &rsps.rsp_data[DATA_IDX_RE];
    modbus_set_slave(ctx, SLAVE_ID_RE);   //从机地址。左前轮：2, 左后轮：3, 右前轮：4, 右后轮：5。

    rc = modbus_read_registers(ctx, 0, 6, prsp->data);

    if (rc == -1)   //读取保持寄存器的值，可读取多个连续输入保持寄存器
    {
        //fprintf(stderr, "L%d %s\n", __LINE__, modbus_strerror(errno));
        fprintf(stderr, "L%d %s\n", __LINE__, modbus_strerror(errno));
        fflush(stdout);

        prsp->unecho_cnt++;
        if(3<= prsp->unecho_cnt){
            prsp->unecho_cnt= 0;
            prsp->unlink= 1;
        }
    }
    else{
        prsp->unlink= 0;
        prsp->unecho_cnt= 0;
    }

    prsp->len= rc;

#ifdef DEBUG_A39C
    qDebug()<<SLAVE_ID_RE<<prsp->len<<hex<<prsp->data[0]<<prsp->data[1]<<prsp->data[2];  //实时重量和状态。
#endif


    //
    emit this->finish(rsps);
    //emit finish(100);
}



void QA39C::do_zero()
{
    int rc;

    //对称重板执行清零操作。
    //左前。
    modbus_set_slave(ctx, SLAVE_ID_LF);   //从机地址。左前轮：2, 左后轮：3, 右前轮：4, 右后轮：5。

    rc = modbus_write_register(ctx, 6, 0xFF00);

    if (rc == -1)   //读取保持寄存器的值，可读取多个连续输入保持寄存器
    {
        fprintf(stderr, "L%d %s\n", __LINE__, modbus_strerror(errno));
        fflush(stdout);

    }

    QThread::msleep(50);


    //左后。
    modbus_set_slave(ctx, SLAVE_ID_LE);   //从机地址。左前轮：2, 左后轮：3, 右前轮：4, 右后轮：5。

    rc = modbus_write_register(ctx, 6, 0xFF00);

    if (rc == -1)   //读取保持寄存器的值，可读取多个连续输入保持寄存器
    {
        fprintf(stderr, "L%d %s\n", __LINE__, modbus_strerror(errno));
        fflush(stdout);

    }

    QThread::msleep(50);


    //右前。
    modbus_set_slave(ctx, SLAVE_ID_RF);   //从机地址。左前轮：2, 左后轮：3, 右前轮：4, 右后轮：5。

    rc = modbus_write_register(ctx, 6, 0xFF00);

    if (rc == -1)   //读取保持寄存器的值，可读取多个连续输入保持寄存器
    {
        //fprintf(stderr, "%s\n", modbus_strerror(errno));
        fprintf(stderr, "L%d %s\n", __LINE__, modbus_strerror(errno));
        fflush(stdout);

    }

    QThread::msleep(50);


    //右后。
    modbus_set_slave(ctx, SLAVE_ID_RE);   //从机地址。左前轮：2, 左后轮：3, 右前轮：4, 右后轮：5。

    rc = modbus_write_register(ctx, 6, 0xFF00);

    if (rc == -1)   //读取保持寄存器的值，可读取多个连续输入保持寄存器
    {
        //fprintf(stderr, "%s\n", modbus_strerror(errno));
        fprintf(stderr, "L%d %s\n", __LINE__, modbus_strerror(errno));
        fflush(stdout);

    }

    QThread::msleep(50);
}



